<?php
/**
 * Created by PhpStorm.
 * User: eValor
 * Date: 2019-03-20
 * Time: 16:57
 */

namespace App\GameService;

use App\WebSocket\WsBase;
use App\Utility\BaseEnum;
use App\Common\AuthCommon;
use App\Common\BaseComm;
use App\Common\GameCommon;
use App\Enum\CardEnum;
use App\GameService\games\PlayHelp;
use App\Enum\SysEnum;

/**
 * 德洲扑克游戏
 */
class Gamepork extends WsBase
{
    protected $allowGameIds = [116];
    
    /**
     * 游戏开始前带入房间筹码显示；
     * @return boolean
     */
    public function showRoomChip() {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0 ; //进游戏房间
        $userid = FALSE;
        try {
            //TODO 登录验证
            $loginUser = $this->LoginPlayUser($userid);
            if (!$loginUser || $userid <= 0 ) { return FALSE; }
            $userPoints = isset($loginUser['points']) ? floatval($loginUser['points']) :0 ;
            if (!$gameRId) {
                $this->ResError(BaseEnum::MSG_0XF2, "游戏类型参数丢失");
                return true;
            }
            
            
            //TODO：查询房间操作
            $roomDetail = BaseComm::GameRoomDetail($gameRId);
            if (!empty($roomDetail)) {
                //房间数据处理（默认为最大携带值）
                $maxInMoney = isset($roomDetail['maxInPoints']) ? floatval($roomDetail['maxInPoints']) : 0; //最大金额；
                if ($userPoints < $maxInMoney) {
                    $maxInMoney = $userPoints;
                }
                //用户默认携带金额为最高配置值
                $userSettMoney = $maxInMoney ; 
                
                //TODO：查询是否有配置过数据(KEY值：用户ID-房间ID)
                $userSett = BaseComm::distMemoryPlayMoney($userid,FALSE);  
                if (!empty($userSett) && isset($userSett[$gameRId]) && floatval($userSett[$gameRId]) > 0) {
                    $userSettMoney = floatval($userSett[$gameRId]);
                }
                
                //展示数据
                $ResData = array(
                    "uid"=>$userid,
                    "roomId"=>$gameRId,
                    "points" => $userPoints,
                    "smallPoints" => isset($roomDetail['smallPoints']) ? floatval($roomDetail['smallPoints']) : 1,
                    "maxInPoints" => $maxInMoney,
                    "userInPoints" => $userSettMoney,
                );
                $this->ResOK($ResData,"查询成功");
                return TRUE;
            }else{
                throw new \Exception("获取房间信息异常",-1);
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("游戏恢复异常". $e->getMessage(), 'user-login');
        }
        return FALSE;
    }
    
    
    /**
     * TODO：游戏开始前带入设置房间筹码
     * @return boolean
     */
    public function goRoomChip() {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0 ;   //进游戏房间
        $setMoney = isset($data['money']) ? floatval($data['money']) : 0 ;          //进游戏房间带的MONEY
        $ifStart= isset($data['start']) ? intval($data['start']) : 0 ;              //是否开始匹配游戏
        
        $userid = FALSE;
        $gameOObject = $this->paramsBean->getGameObject();
        try {
            
            //TODO 登录验证
            $loginUser = $this->LoginPlayUser($userid);
            if (!$loginUser || $userid <= 0 ) { return FALSE; }
            
            $username = isset($loginUser["name"]) ? $loginUser["name"] : "";
            $userPoints = isset($loginUser['points']) ? floatval($loginUser['points']) :0 ;
            if (!$gameRId || !$setMoney || $setMoney > $userPoints) {                   //不超过用户余额
                $this->ResError(BaseEnum::MSG_0XF2, "游戏类型参数丢失",SysEnum::RETURN_MSG_LEVEL_2);
                return true;
            }
            
            //TODO：查询房间操作
            $roomDetail = BaseComm::GameRoomDetail($gameRId);
            $gameID = isset($roomDetail['gameId']) ? intval($roomDetail['gameId']) : 0;
            
            //TODO 判断是否开放这个游戏
            if($gameID >0 && $this -> pullGameStatus($gameID,$loginUser,FALSE) === FALSE){
                $this->ResError(BaseEnum::MSG_0XF5,"该游戏暂未开放，请重试", SysEnum::RETURN_MSG_LEVEL_2);           //重新刷新
                return TRUE;
            }
            
            
            if (empty($roomDetail) || $gameID <= 0 || !in_array($gameID, $this->allowGameIds,TRUE)) {
                throw new \Exception("获取房间信息异常", BaseEnum::MSG_0XF6);
            }
            
            $gameName = isset($roomDetail["gpKey"]) ? $roomDetail["gpKey"] : "";
            if (!empty($roomDetail)) {
                //配置值 : 房间数据处理（最小携带）
                $minInMoney = isset($roomDetail['smallPoints']) ? floatval($roomDetail['smallPoints']) : 0;         //最大金额；
                $maxInMoney = isset($roomDetail['maxInPoints']) ? floatval($roomDetail['maxInPoints']) : 0;         //最大金额；
                $roomEveryPots = isset($roomDetail['everyPoints']) ? floatval($roomDetail['everyPoints']) : 0;      //最大盲注金额
                $startInMoney = isset($roomDetail['startInPoints']) ? floatval($roomDetail['startInPoints']) : 0;      //前注金额
                $smallBet = floatval($roomEveryPots/2);         //小盲注大小
                
                //用户默认携带金额为最高配置值
                $userSettMoney = $maxInMoney ;
                if ($setMoney > 0 && $minInMoney <= $setMoney) {  //满足条件
                    $userSettMoney = $setMoney;
                }
                
                $userSett = BaseComm::distMemoryPlayMoney($userid,FALSE);
                if(!$userSett) $userSett = [];
                $userSett[$gameRId] = $userSettMoney; //用户携带的金额
                
                //保存当前数据是否有配置过数据(KEY值：用户ID-房间ID)
                BaseComm::distMemoryPlayMoney($userid,TRUE,$userSett);
                
                //TODO：游戏开始 =======> 加入匹配列表操作； 
                if(isset($ifStart) && intval($ifStart) === 1){
                    $wjInfo = array(
                        "uid" => $userid,
                        'name' => $username,
                        "lineCode" => $loginUser['lineCode'] ?? "",                                         // 玩家代理标记
                        "isNation" => isset($loginUser['isNation']) ? intval($loginUser['isNation']) : 0,   // 玩家身份信息
                        "agentId" => isset($loginUser['recUid']) ? intval($loginUser['recUid']) : 0,        // 代理用户ID
                        "sex" => isset($loginUser['gender']) ? intval($loginUser['gender']) : 0,            // 性别
                        "head_id" => isset($loginUser['head_url']) ? intval($loginUser['head_url']) : 0,    // 头像
                        "fd" => $loginFd,
                        "points" => $userSettMoney,  //携带的金额
                        "play_lun" => 0,        // 第几轮操作
                        "play_hand" => -1,      // 当前轮的操作类型 (-1未操作 ,0-弃牌，1-过牌，2-跟注，3 加注)
                        "play_lunmoney" => 0.0, // 当前轮操作金额
                        "seatNo" => - 1,        // 默认座位为0
                        "mainflag" => 0,        // 标识为闲家，默认0
                        "blind_money" => 0.0,   // 盲注金额
                        "betmoney"=> 0,
                        "total_money" => 0.00   //用户总金额
                    );
                    
                    // TODO：查询是否有未开局房间；(等待开局，返回是否可以开)
                    $getFreeRoom = GameCommon::joinXYRooms($gameRId, $roomDetail, $wjInfo);
                    $gameNo = isset($getFreeRoom["roomNo"]) ? $getFreeRoom["roomNo"] : "";             // 房间编号内容
                    $players = isset($getFreeRoom['info']) ? $getFreeRoom['info'] : false;              // 通知在线的其它用户；有新玩家上线
                    
                    //TODO：匹配成功操作
                    if (isset($getFreeRoom) && ! empty($getFreeRoom) && isset($getFreeRoom['ifOpen']) && intval($getFreeRoom['ifOpen']) > 0 && ! empty($gameNo) && !empty($players)) {
                        $allFds = ! empty($players) ? array_column($players, 'fd', "uid") : false;      // 玩家FD列表；要及时推着在线等用户；
                        $gData = BaseComm::distMemoryRooms($gameNo);
                        BaseEnum::Logger('匹配成功：开始游戏 (GamePork)---goRoomChip =>' . json_encode([$gameNo,$gData]), 'user-login');
                        $gameResult = ["gstart"=>1,"gameNo"=>$gameNo,"deskMoney"=>0];  // 有开局，(自动匹配)直接进入；要写DB操作；
                        //加入详细数据；
                        $gameResult["roomInfo"] = array("gameId"=>$gameID,"everyPoints"=>$roomEveryPots,"smallPoints"=>$minInMoney,"maxInMoney"=> $maxInMoney,"total"=>5); //默认为第一局
                        $deskMoney = 0;
                        //TODO大小盲注值：取第一位为庄家：顺时方向小盲注，和大盲注下注
                        foreach ($players as $seatNo => & $wjInfo){
                            $beforeMoney = $startInMoney ;                  //前注金额
                            if($seatNo === 0){
                                $wjInfo["mainflag"] =  1;                   //第一位为庄家
                            }else if ($seatNo === 1) {
                                $beforeMoney += $smallBet;                  // 第二个玩家下小盲注
                            }else if ($seatNo === 2) {
                                $beforeMoney += $roomEveryPots;             // 第三个玩家下小盲注
                            }
                            $wjInfo['play_lun'] = 0;                          // 轮
                            $wjInfo['blind_money'] = $beforeMoney;            // 大/小盲注
                            $wjInfo['total_money'] = $beforeMoney;            // 大/小盲注
                            $wjInfo['play_lunmoney'] = $beforeMoney;          // 当前这一轮的所有玩家下注金额都要一样
                            $deskMoney = bcadd($deskMoney, $beforeMoney , 2); //桌面上的分数
                        }
                        
                        /************************************需要开局插入DB的游戏**********************************/
                        $roomDetail["users_num"] = sizeof($players);
                        $roomDetail["users"] = $players;        // 游戏数据
                        $dbEx = GameCommon::createRoomsPlayinfo($gameRId, $gameNo, $roomDetail, $userid);   // 房间落地写入DB并开始发牌
                        // 写入成功，游戏开始
                        if ($dbEx === true) {
                            BaseEnum::Logger("房间成功写入DB：Gamepork-(goo)-，开始游戏[deskmoney={$deskMoney}]---->>>" . $gameNo, 'user-login');
                        }else{
                            BaseEnum::Logger("房间写入DB失败：Gamepork-(goo)-，写数据失败!!!! [deskmoney={$deskMoney}]---->>>" . $gameNo, 'user-login');
                            return FALSE;
                        }
                        
                        $gameResult["deskMoney"] = floatval($deskMoney);
                        $gameResult["players"] = $players;
                        $gData["playTimes"] = 1 ;                           //开始第一轮
                        $gData["lastSiteNo"] = 2 ;                          //最后下注的位置索引刚开始为第四个人； 轮回操作(0-1-2-3 - 0-1-2-3....)
                        $gData["deskMoney"] = floatval($deskMoney);         //桌面保存的金额
                        $gData["lists"] = $players ;                        //修改内存
                        BaseComm::distMemoryRooms($gameNo,TRUE,$gData);
                        
                        //TODO：通知所有玩家进入游戏 
                        $gamedata = array('m'=>BaseEnum::XYM_0X16,"data"=> $gameResult);
                        AuthCommon::pushFrontWeb($allFds,json_encode($gamedata));
                        //游戏开局第一步结束 进入游戏发牌处理
                        if (!$gameOObject || empty($gameOObject) || (!empty($gameOObject) && isset($gameOObject -> baseGameName) && $gameOObject -> baseGameName != $gameName)) {
                            $gameOObject = BaseEnum::getClassObject($gameName, false);           // 创建对象；
                            BaseEnum::Logger('实例化为空：新实例化一个操作；-->>>' . json_encode(['gName'=> $gameName,"obj"=> $gameOObject]), 'user-login');
                        }
                        if (!empty($gameOObject)) {
                            BaseEnum::Logger('实例化：变更Name (getGameObject)--->>>' . json_encode($gameOObject), 'user-login');
                            BaseEnum::Logger("开始进入互动：Gamespork-(goRoomChip)-getClassObject，[{$gameName}]---->>>" . json_encode($gameOObject), 'user-login');
                            if (! empty($gameOObject) && method_exists($gameOObject, "asycStartGame")) {
                                // 启动游戏操作
                                $gameOObject->setGameStatus("P-" . CardEnum::GAME_STEP_0); // 设置游戏状态；
                                BaseEnum::Logger('实例化对象：' . json_encode($gameOObject), 'user-login');
                                BaseEnum::Logger("开始进入互动：Games-(goRoomChip)-getClassObject，[{$gameName}]---->>>" . $gameNo, 'user-login');
                                $gameOObject -> asycStartGame($gameNo, $gameRId, $roomDetail);
                            }
                        } else {
                            BaseEnum::Logger("互动失败：Gamespork-(goRoomChip)-getClassObject，[{$gameName}]----失败!!!!" . json_encode($gameOObject), 'user-login');
                        }
                    }else{
                        //匹配超时处理
                        BaseEnum::Logger('等待其它玩家加入： (GamePork)---goRoomChip =>' . json_encode($wjInfo), 'user-login');
                        
                        //TODO 启动机器人等待
                        $this->joinIntoRobots($gameRId,$loginFd,$userid,$roomDetail,$gameOObject);
                        
                        //进入等待(等待匹配其它玩家)
                        $this->waitStartTimeOut($gameRId, $loginFd,$userid);
                    }
                    return FALSE;   //游戏匹配中 不需要返回处理
                }
                //提醒前端
                $this->ResSUCCESS(1,"SUCCESS");
                return TRUE;
            }else{
                throw new \Exception("获取房间信息异常",-1);
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("游戏恢复异常". $e->getMessage(), 'user-login');
        }
        return FALSE;
    }
    
    /**
     * TODO　玩家下注操作
     */
    public function goBets() {
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0 ;   //游戏房间
        $gameNo = isset($data['gameNo']) ? $data['gameNo'] : "" ;                   //游局号
        $htype = isset($data['htype']) ? intval($data['htype']) : 0 ;               //操作类型
        $money = isset($data['money']) ? floatval($data['money']) : 0 ;
        $userid = FALSE;
        try {
            //TODO 登录验证
            $loginUser = $this->LoginPlayUser($userid);
            if (!$loginUser || $userid <= 0 ) { return FALSE; }
            $userPoints = isset($loginUser['points']) ? floatval($loginUser['points']) :0;
            if (!$gameRId || !$gameNo) {
                $this->ResError(BaseEnum::MSG_0XF2, "游戏类型参数丢失");
                return true;
            }
            
            //TODO 游戏数据
            $fjDetail = BaseComm::distMemoryRooms($gameNo,FALSE);        
            $playList = isset($fjDetail["lists"]) ? $fjDetail["lists"] : FALSE ;
            $playFds = !empty($playList) ? array_column($playList, "fd","seatNo") : false ;
            $curLunNum = isset($fjDetail["playTimes"]) ? intval($fjDetail["playTimes"]) : 1 ; //取第几轮；
            $deskMoney = isset($fjDetail["deskMoney"]) ? floatval($fjDetail["deskMoney"]) :1 ;
            
            //取座位号
            $loginSiteNo = !empty($playFds) ? array_search($loginFd, $playFds) : -1; //登录用户所在位置；
            $wjInfo = isset($playList[$loginSiteNo]) ? $playList[$loginSiteNo]  : FALSE ;
            if($loginSiteNo < 0 || !$wjInfo) return FALSE;
            $lun_Val = isset($wjInfo['play_lun'])  ?  intval($wjInfo['play_lun']) : -1;
            
            
            //TODO  登录玩家信息变更
            $isFirst =($lun_Val === $curLunNum) ? FALSE : TRUE; //本轮是否第一次操作
            $isBlildFirst =($lun_Val === 0 && $loginSiteNo == 1) ? TRUE : FALSE; //小盲注时不能清理
            $wjInfo['play_lun'] = $curLunNum;           // 轮
            if($isFirst  && $isBlildFirst !== TRUE){
                $wjInfo['play_lunmoney'] = 0;           //第一次操作下注额 清 0 (小盲注第一次不清零)
            }
            //TODO  跟注、加注 type = 2,3
            if (in_array($htype, [CardEnum::DZPK_TYPE_2,CardEnum::DZPK_TYPE_3],TRUE) && $money > 0) {   
                $oldMoney = isset($wjInfo['total_money']) ? $wjInfo['total_money'] : 0;
                $currmoney = $money;
                if(isset($wjInfo['play_lunmoney']) && floatval($wjInfo['play_lunmoney']) > 0){
                    $currmoney = bcadd($wjInfo['play_lunmoney'], $money,2 );        // 玩家本轮总额
                    BaseEnum::Logger("玩家{$loginSiteNo}号位玩家跟注操作： (GamePork)---type={$htype},money={$money}  跟注后的总金额为 =>" .$currmoney, 'user-login');
                }
                $wjInfo['play_hand'] = $htype;
                $wjInfo['play_lunmoney'] = floatval($currmoney);
                $wjInfo['betmoney'] = bcadd($oldMoney, $money,3);
                $wjInfo['total_money'] = bcadd($oldMoney, $money,3);               // 玩家下注总额
                $fjDetail["deskMoney"] =   floatval(bcadd($deskMoney, $money,3));  //TODO 桌面总额变化
            }
            //TODO  过牌操作  type = 1
            else if($htype === CardEnum::DZPK_TYPE_1){
                $wjInfo['play_hand'] = CardEnum::DZPK_TYPE_1;
            }
            //TODO  弃牌操作  type = 0
            else if($htype === CardEnum::DZPK_TYPE_0){
                $wjInfo['play_hand'] = CardEnum::DZPK_TYPE_0;
            }
            //TODO  触发 ALL IN  type = 4
            else if($htype === CardEnum::DZPK_TYPE_4){      //所有的话，后面的玩家只有两种选择====> 弃牌和ALL IN
                $oldMoney = isset($wjInfo['total_money']) ? $wjInfo['total_money'] : 0;
                $moneyAll = floatval($wjInfo["points"]); 
                $wjInfo['play_hand'] = CardEnum::DZPK_TYPE_4;
                $wjInfo['total_money'] = floatval(bcadd($oldMoney, $moneyAll,3));               // 玩家下注总额
            }
            //TODO  保存玩家游戏数据
            $playList[$loginSiteNo] = $wjInfo;
            $fjDetail["lists"]= $playList;
            BaseEnum::Logger("玩家操作： (GamePork)---type={$htype},money={$money}  info=>" . json_encode($wjInfo), 'user-login');
            BaseComm::distMemoryRooms($gameNo,TRUE,$fjDetail);
            PlayHelp::getInstance()->setCommTimerStop($gameNo,TRUE);    //停掉定时器
            return FALSE;
        } catch (\Throwable $e) {
            
            BaseEnum::Logger("玩家下注异常". $e->getMessage(), 'user-login');
        }
        return FALSE;
    }
    
    

}